package jnpf.fico.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.IterUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jnpf.engine.entity.FlowTaskEntity;
import jnpf.engine.service.FlowTaskService;
import jnpf.exception.WorkFlowException;
import jnpf.fico.entity.ZcBillEntity;
import jnpf.fico.entity.ZcBillItemEntity;
import jnpf.fico.mapper.ZcBillItemMapper;
import jnpf.fico.mapper.ZcBillMapper;
import jnpf.fico.model.bill.*;
import jnpf.fico.model.operate.ZcBillOperateMainVo;
import jnpf.fico.model.operate.ZcBillOperatePagination;
import jnpf.fico.service.ZcBillItemService;
import jnpf.fico.service.ZcBillOperateService;
import jnpf.fico.service.ZcBillService;
import jnpf.model.visiual.superQuery.ConditionJsonModel;
import jnpf.model.visiual.superQuery.SuperQueryConditionModel;
import jnpf.model.visiual.superQuery.SuperQueryJsonModel;
import jnpf.permission.model.authorize.AuthorizeConditionModel;
import jnpf.permission.service.AuthorizeService;
import jnpf.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 账单信息
 * 版本： V3.2.0
 * 版权： 智果云科技（https://www.jnpfsoft.com）
 * 作者： JNPF开发平台组
 * 日期： 2024-10-22
 */
@Service
public class ZcBillServiceImpl extends ServiceImpl<ZcBillMapper, ZcBillEntity> implements ZcBillService {


    @Autowired
    private GeneraterSwapUtil generaterSwapUtil;

    @Autowired
    private UserProvider userProvider;

    @Autowired
    private AuthorizeService authorizeService;


    @Autowired
    private ZcBillItemService zcBillItemService;

    @Autowired
    private ZcBillItemMapper zcBillItemMapper;

    @Autowired
    private FlowTaskService flowTaskService;

    @Autowired
    private ZcBillOperateService billOperateService;


    @Override
    public List<ZcBillEntity> getList(ZcBillPagination zcBillPagination) {
        return getTypeList(zcBillPagination, zcBillPagination.getDataType());
    }

    @Override
    public List<ZcBillEntity> getTypeList(ZcBillPagination zcBillPagination, String dataType) {
        String userId = userProvider.get().getUserId();
        List<String> AllIdList = new ArrayList();
        List<List<String>> intersectionList = new ArrayList<>();
        int total = 0;
        int zcBillNum = 0;
        QueryWrapper<ZcBillEntity> zcBillQueryWrapper = new QueryWrapper<>();
        int zcBillItemNum = 0;
        QueryWrapper<ZcBillItemEntity> zcBillItemQueryWrapper = new QueryWrapper<>();
        long zcBillItemcount = zcBillItemService.count();
        List<String> allSuperIDlist = new ArrayList<>();
        String superOp = "";
        if (ObjectUtil.isNotEmpty(zcBillPagination.getSuperQueryJson())) {
            SuperQueryJsonModel superQueryJsonModel = JsonUtil.getJsonToBean(zcBillPagination.getSuperQueryJson(), SuperQueryJsonModel.class);
            String matchLogic = superQueryJsonModel.getMatchLogic();
            List<ConditionJsonModel> superQueryList = JsonUtil.getJsonToList(superQueryJsonModel.getConditionJson(), ConditionJsonModel.class);
            for (ConditionJsonModel conditionjson : superQueryList) {
                Map<String, Object> map = JsonUtil.stringToMap(conditionjson.getAttr());
                Map<String, Object> configMap = JsonUtil.stringToMap(map.get("__config__").toString());
                String tableName = configMap.get("relationTable") != null ? String.valueOf(configMap.get("relationTable")) : String.valueOf(configMap.get("tableName"));
                if (map.get("multiple") != null) {
                    if (Boolean.valueOf(String.valueOf(map.get("multiple"))) && ObjectUtil.isNull(conditionjson.getFieldValue())) {
                        conditionjson.setFieldValue("[]");
                    }
                }
                conditionjson.setTableName(tableName);
            }
            List<String> allSuperList = new ArrayList<>();
            List<List<String>> intersectionSuperList = new ArrayList<>();
            int zcBillNum1 = 0;
            QueryWrapper<ZcBillEntity> zcBillSuperWrapper = new QueryWrapper<>();
            zcBillNum1 = generaterSwapUtil.getCondition(new SuperQueryConditionModel(zcBillSuperWrapper, superQueryList, matchLogic, "zcBill")
                    , new ZcBillEntity(), zcBillNum1);
            if (zcBillNum1 > 0) {
                List<String> zcBillList = this.list(zcBillSuperWrapper).stream().map(ZcBillEntity::getId).collect(Collectors.toList());
                allSuperList.addAll(zcBillList);
                intersectionSuperList.add(zcBillList);
            }
            int zcBillItemNum1 = 0;
            QueryWrapper<ZcBillItemEntity> zcBillItemSuperWrapper = new QueryWrapper<>();
            zcBillItemNum1 = generaterSwapUtil.getCondition(new SuperQueryConditionModel(zcBillItemSuperWrapper, superQueryList, matchLogic, "zcBillItem")
                    , new ZcBillItemEntity(), zcBillItemNum1);
            if (zcBillItemNum1 > 0 && zcBillItemcount > 0) {
                List<String> zcBillItemList = zcBillItemService.list(zcBillItemSuperWrapper).stream().map(ZcBillItemEntity::getParentid).collect(Collectors.toList());
                allSuperList.addAll(zcBillItemList);
                intersectionSuperList.add(zcBillItemList);
            }
            superOp = matchLogic;
            //and or
            if (matchLogic.equalsIgnoreCase("and")) {
                allSuperIDlist = generaterSwapUtil.getIntersection(intersectionSuperList);
            } else {
                allSuperIDlist = allSuperList;
            }
        }
        boolean pcPermission = false;
        boolean appPermission = false;
        boolean isPc = ServletUtil.getHeader("jnpf-origin").equals("pc");
        if (isPc && pcPermission) {
            if (!userProvider.get().getIsAdministrator()) {
                Object zcBillObj = authorizeService.getCondition(new AuthorizeConditionModel(zcBillQueryWrapper, zcBillPagination.getMenuId(), "zcgl_cw_bill"));
                if (ObjectUtil.isEmpty(zcBillObj)) {
                    return new ArrayList<>();
                } else {
                    zcBillQueryWrapper = (QueryWrapper<ZcBillEntity>) zcBillObj;
                    zcBillNum++;
                }
                Object zcBillItemObj = authorizeService.getCondition(new AuthorizeConditionModel(zcBillItemQueryWrapper, zcBillPagination.getMenuId(), "zcgl_cw_bill_item"));
                if (ObjectUtil.isEmpty(zcBillItemObj)) {
                    return new ArrayList<>();
                } else {
                    zcBillItemQueryWrapper = (QueryWrapper<ZcBillItemEntity>) zcBillItemObj;
                    zcBillItemNum++;
                }
            }
        }
        if (!isPc && appPermission) {
            if (!userProvider.get().getIsAdministrator()) {
                Object zcBillObj = authorizeService.getCondition(new AuthorizeConditionModel(zcBillQueryWrapper, zcBillPagination.getMenuId(), "zcBill"));
                if (ObjectUtil.isEmpty(zcBillObj)) {
                    return new ArrayList<>();
                } else {
                    zcBillQueryWrapper = (QueryWrapper<ZcBillEntity>) zcBillObj;
                    zcBillNum++;
                }


                Object zcBillItemObj = authorizeService.getCondition(new AuthorizeConditionModel(zcBillItemQueryWrapper, zcBillPagination.getMenuId(), "zcBillItem"));
                if (ObjectUtil.isEmpty(zcBillItemObj)) {
                    return new ArrayList<>();
                } else {
                    zcBillItemQueryWrapper = (QueryWrapper<ZcBillItemEntity>) zcBillItemObj;
                    zcBillItemNum++;
                }


            }
        }
        if (isPc) {
            if (ObjectUtil.isNotEmpty(zcBillPagination.getPaymentBillNo())) {
                zcBillNum++;
                zcBillQueryWrapper.lambda().like(ZcBillEntity::getPaymentBillNo, zcBillPagination.getPaymentBillNo());
            }

        }
        if (zcBillItemNum > 0) {
            List<String> zcBillItemIdList = zcBillItemService.list(zcBillItemQueryWrapper).stream().filter(t -> StringUtil.isNotEmpty(t.getParentid())).map(t -> t.getParentid()).collect(Collectors.toList());
            long count = zcBillItemService.count();
            if (count > 0) {
                intersectionList.add(zcBillItemIdList);
            }
            AllIdList.addAll(zcBillItemIdList);
        }
        total += zcBillItemNum;
        List<String> intersection = generaterSwapUtil.getIntersection(intersectionList);
        if (total > 0) {
            if (intersection.size() == 0) {
                intersection.add("jnpfNullList");
            }
            zcBillQueryWrapper.lambda().in(ZcBillEntity::getId, intersection);
        }
        //是否有高级查询
        if (StringUtil.isNotEmpty(superOp)) {
            if (allSuperIDlist.size() == 0) {
                allSuperIDlist.add("jnpfNullList");
            }
            List<String> finalAllSuperIDlist = allSuperIDlist;
            zcBillQueryWrapper.lambda().and(t -> t.in(ZcBillEntity::getId, finalAllSuperIDlist));
        }

        //排序
        if (StringUtil.isEmpty(zcBillPagination.getSidx())) {
            zcBillQueryWrapper.lambda().orderByDesc(ZcBillEntity::getId);
        } else {
            try {
                String sidx = zcBillPagination.getSidx();
                ZcBillEntity zcBillEntity = new ZcBillEntity();
                Field declaredField = zcBillEntity.getClass().getDeclaredField(sidx);
                declaredField.setAccessible(true);
                String value = declaredField.getAnnotation(TableField.class).value();
                zcBillQueryWrapper = "asc".equals(zcBillPagination.getSort().toLowerCase()) ? zcBillQueryWrapper.orderByAsc(value) : zcBillQueryWrapper.orderByDesc(value);
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            }
        }
        if ("0".equals(dataType)) {
            if ((total > 0 && AllIdList.size() > 0) || total == 0) {
                Page<ZcBillEntity> page = new Page<>(zcBillPagination.getCurrentPage(), zcBillPagination.getPageSize());
                IPage<ZcBillEntity> userIPage = this.page(page, zcBillQueryWrapper);
                return zcBillPagination.setData(userIPage.getRecords(), userIPage.getTotal());
            } else {
                List<ZcBillEntity> list = new ArrayList();
                return zcBillPagination.setData(list, list.size());
            }
        } else {
            return this.list(zcBillQueryWrapper);
        }
    }


    @Override
    public ZcBillEntity getInfo(String id) {
        QueryWrapper<ZcBillEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ZcBillEntity::getId, id);
        return this.getOne(queryWrapper);
    }

    @Override
    public void create(ZcBillEntity entity) {
        this.save(entity);
    }

    @Override
    public boolean update(String id, ZcBillEntity entity) {
        return this.updateById(entity);
    }

    @Override
    public void delete(ZcBillEntity entity) {
        if (entity != null) {
            this.removeById(entity.getId());
        }
    }

    //子表方法
    @Override
    public List<ZcBillItemEntity> getZcBillItemList(String id, ZcBillPagination zcBillPagination) {
        QueryWrapper<ZcBillItemEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper = zcBillItemService.getChild(zcBillPagination, queryWrapper);
        queryWrapper.lambda().eq(ZcBillItemEntity::getParentid, id);
        return zcBillItemService.list(queryWrapper);
    }

    @Override
    public List<ZcBillItemEntity> getZcBillItemList(String id) {
        QueryWrapper<ZcBillItemEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ZcBillItemEntity::getParentid, id);
        return zcBillItemService.list(queryWrapper);
    }

    //列表子表数据方法


    //验证表单唯一字段
    @Override
    public boolean checkForm(ZcBillForm form, int i) {
        int total = 0;
        boolean isUp = StringUtil.isNotEmpty(form.getId()) && !form.getId().equals("0");
        String id = "";
        if (isUp) {
            id = form.getId();
        }
        if (form.getBillItems() != null) {
        }
        if (total > 0) {
            return true;
        }
        return false;
    }

    @Override
    public  void reviewBill(List<String> ids) {
        List<ZcBillEntity> bills = listByIds(ids);

        if(CollUtil.isEmpty(bills)) {
            throw new RuntimeException("未查询到对应账单信息");
        }

        // 更新核账信息
        String userId = userProvider.get().getUserId();

        bills.forEach(bill -> {
            bill.setIsReviewBill(1);
            bill.setReviewBillUser(userId);
            bill.setReviewBillTime(DateUtil.date());
        });


        updateBatchById(bills);
    }

    @Override
    public ZcBillSumMoneyDTO getSumMoney() {
        ZcBillSumMoneyDTO zcBillSumMoneyDTO = baseMapper.getSumMoney();
        return zcBillSumMoneyDTO;
    }

    @Override
    public ZcBillInfoDTO getBillInfo(String id) {
        ZcBillEntity zcBillEntity = baseMapper.selectById(id);
        ZcBillInfoDTO zcBillInfoDTO = new ZcBillInfoDTO();
        BeanUtil.copyProperties(zcBillEntity,zcBillInfoDTO);
        Date planReceiptDate = zcBillInfoDTO.getPlanReceiptDate();
        if(ObjectUtil.isNotNull(planReceiptDate)){
            zcBillInfoDTO.setPlanReceiptDateStr(DateUtil.format(planReceiptDate,"yyyy-MM-dd"));
        }

        //封装计费周期
        Date expenseStartDate = zcBillEntity.getExpenseStartDate();
        Date expenseEndDate = zcBillEntity.getExpenseEndDate();
        if(ObjectUtil.isNotNull(expenseStartDate)&&ObjectUtil.isNotNull(expenseEndDate)){
            zcBillInfoDTO.setExpenseCycleDate(jnpf.util.DateUtil.dateToString(expenseStartDate, "yyyy-MM-dd")+"至"+ jnpf.util.DateUtil.dateToString(expenseEndDate, "yyyy-MM-dd"));
        }

        //获取费用项明细
        List<ZcBillItemEntity> itemEntities = zcBillItemMapper.selectList(new QueryWrapper<ZcBillItemEntity>()
                .eq("F_ParentId", id)
        );

        List<ZcBillCostInfoDTO> zcBillCostInfoDTOS = new ArrayList<>();
        if(IterUtil.isNotEmpty(itemEntities)){
            // 根据 expenseItem 和 status 分组
            Map<String, List<ZcBillItemEntity>> groupedItems = itemEntities.stream()
                    .collect(Collectors.groupingBy(item -> item.getExpenseItem() + "|" + item.getStatus()));
            groupedItems.forEach((key, items) -> {
                String[] keys = key.split("\\|"); // 分割 key 获取 expenseItem 和 status
                String expenseItem = keys[0];
                Integer status = Integer.parseInt(keys[1]);

                //封装本金
                String principal = items.stream()
                        .map(item -> String.format("应收(本)金额：%s<br> 实际应收：%s<br>已收(本)金额：%s<br>未收(本)金额：%s<br> 减免金额：%s<br> 结转抵扣：%s<br> 待收金额：%s<br> 应退金额：%s<br> 待退金额 %s<br> 已退金额：%s<br>",
                                item.getReceiveAmount()==null?0:item.getReceiveAmount(),
                                item.getRealAmount()==null?0:item.getRealAmount(),
                                item.getReceivedAmount()==null?0:item.getReceivedAmount(),
                                item.getPendAmount()==null?0:item.getPendAmount(),

                                item.getReduceAmount()==null?0:item.getReduceAmount(),
                                item.getOverAmount()==null?0:item.getOverAmount(),
                                item.getPendOverdueAmount()==null?0:item.getPendOverdueAmount(),
                                item.getPlanRefundAmount()==null?0:item.getPlanRefundAmount(),
                                item.getPendRefundAmount()==null?0:item.getPendRefundAmount(),
                                item.getRefundAmount()==null?0:item.getRefundAmount()
                                )
                        )
                        .collect(Collectors.joining("<br>"));

                //封装滞纳金
                String lateFee = items.stream()
                        .map(item -> String.format("应收滞纳金：%s<br> 已收滞纳金：%s<br> 减免滞纳金：%s<br>待收滞纳金：%s<br>",
                                item.getReceiveOverdueAmount()==null?0:item.getReceiveOverdueAmount(),
                                item.getRealOverdueAmount()==null?0:item.getRealOverdueAmount(),
                                item.getReduceOverdueAmount()==null?0:item.getReduceOverdueAmount(),
                                item.getPendOverdueAmount()==null?0:item.getPendOverdueAmount()
                                )
                        )
                        .collect(Collectors.joining("<br>"));

                ZcBillCostInfoDTO zcBillCostInfoDTO = new ZcBillCostInfoDTO(expenseItem,status,principal,lateFee,items.get(0));
                zcBillCostInfoDTOS.add(zcBillCostInfoDTO);
            });
        }
        zcBillInfoDTO.setZcbillitemList(zcBillCostInfoDTOS);

        // 获取账单操作记录列表
        ZcBillOperatePagination selectOperateParam = new ZcBillOperatePagination();
        selectOperateParam.setBillId(zcBillInfoDTO.getId());
        selectOperateParam.setCurrentPage(1);
        selectOperateParam.setPageSize(9999);
        List<ZcBillOperateMainVo> operateMainVoList = billOperateService.pageBillOperateList(selectOperateParam).getRecords();

        if(CollUtil.isNotEmpty(operateMainVoList)){
            // 获取减免记录
            zcBillInfoDTO.setReduceList(operateMainVoList.stream().filter(item -> item.getType() == 1).collect(Collectors.toList()));
            // 获取退款记录
            zcBillInfoDTO.setRefundList(operateMainVoList.stream().filter(item -> item.getType() == 2).collect(Collectors.toList()));
        }

        // TODO 收支记录
        zcBillInfoDTO.setSzList(null);

        return zcBillInfoDTO;
    }

    @Override
    public void updateBill(String taskId) {
        // 通过taskId获取流程中账单变更参数
        String formJson = null;
        try{
            FlowTaskEntity flowTask = flowTaskService.getInfo(taskId);
            formJson = flowTask.getFlowFormContentJson();
        } catch (WorkFlowException e) {
            e.printStackTrace();
        }

        // 转换参数实体
        ZcBillForm billForm = JSON.parseObject(formJson, ZcBillForm.class);

        // TODO 校验，什么时候不能进行修改

        // 主表信息更新
        ZcBillEntity billEntity = BeanUtil.copyProperties(billForm,ZcBillEntity.class);
        updateById(billEntity);

        // 费用项更新
        if (CollUtil.isNotEmpty(billForm.getBillItems())) {
            List<ZcBillItemEntity> items = BeanUtil.copyToList(billForm.getBillItems(),ZcBillItemEntity.class);
            zcBillItemService.updateBatchById(items);
        }

    }


}
